/*
 * Precompilador.cpp
 */

#include "Precompilador.h"

Precompilador::Precompilador(HttpParser &hParser) {
	this->nivelRecursividad = 0;
	this->directorioArchivos.clear();
	this->httpParser = &hParser;
}

Precompilador::Precompilador(const std::string &directArch) {
	this->nivelRecursividad = 0;
	this->directorioArchivos.assign(directArch);
	this->httpParser = NULL;
}

bool Precompilador::precompilarArchivo(const std::string &nombArch) {
	// Verifico condición de corte de recursividad
	++this->nivelRecursividad;
	if(this->nivelRecursividad >= MAX_NIVEL_RECURSIVIDAD) {
		std::cout << "La anidación de includes a superado el máximo.\n<br>";
		return false;
	}
	// Creo un parser asociado al archivo según corresponda
	Parser* parser;
	if(this->directorioArchivos.empty())
		parser = new Parser(this->httpParser->getArchivo(nombArch));
	else
		parser = new Parser(this->directorioArchivos, nombArch);
	// Verifico que el parser se haya creado correctamente
	bool resultado = false;
	if(parser->estadoValido()) {
		std::string	bufferLect;
		bool malFormado = false;
		while(!malFormado && parser->parsearLinea(bufferLect)) {
			// Verifico si es una directiva del precompilador
			if(parser->esDirectiva(bufferLect)) {
				// Separo la directiva de su valor e intento procesarla
				std::string directivLeida = parser->getDirectiva(bufferLect);
				std::string valorDirectiv = parser->getValorDirectiva(bufferLect);
				malFormado = !this->procesarDirectivas(parser, directivLeida, valorDirectiv);
			} else if (this->pilaIfs.validezUltimaDirectiva()) {
				// Analizo lineas que no son directivas al precompilador si corresponde
				parser->reemplazarDefiniciones(bufferLect, this->tablaDef);
				std::cout << bufferLect << "\n<br>";
			}
		}
		resultado = !malFormado;
	} else {
		// Armo la ruta del nombre del archivo
		std::string nombArchComp(this->directorioArchivos);
		nombArchComp.append(nombArch);
		std::cout << "No se encontró el archivo " << nombArchComp << "\n<br>";
		resultado = false;
	}
	--this->nivelRecursividad;
	delete parser;
	return resultado;
}

bool Precompilador::procesarDirectivas(const Parser* parser, const std::string &directivLeida,
		const std::string &valorDirectiv) {
	bool resultado = true;
	if(directivLeida == "define" &&	this->pilaIfs.validezUltimaDirectiva()) {
		std::stringstream ss(valorDirectiv);
		std::string nombDef, valorDef;
		// Verifico que la definicion tenga nombre y no empieze con un número
		if(ss >> nombDef && isdigit((int)nombDef[0]) == 0) {
			char valorTemp;
			ss >> std::noskipws;
			while(ss >> valorTemp) {
				valorDef.push_back(valorTemp);
			}
			resultado = this->tablaDef.agregarDefinicion(nombDef, valorDef);
		} else {
			resultado = false;  // No hay nombre en la definicion
		}
	} else if (directivLeida == "include" &&
			this->pilaIfs.validezUltimaDirectiva()) {
		std::string nombreArchivo = parser->tokenizarDobleLado(valorDirectiv,
				SEP_NOMBRE_ARCHIVO);
		if(!nombreArchivo.empty())
			resultado = precompilarArchivo(nombreArchivo);
		else
			resultado = false;
	} else if (directivLeida == "ifdef") {
		// Intento procesar la directiva condicional positiva
		resultado = this->procDirectivCondicion(valorDirectiv, true);
	} else if (directivLeida == "ifndef") {
		// Intento procesar la directiva condicional negativa
		resultado = this->procDirectivCondicion(valorDirectiv, false);
	} else if (directivLeida == "else") {
		resultado = this->pilaIfs.marcarElse();
	} else if (directivLeida == "endif") {
		resultado = this->pilaIfs.marcarEndIf();
	}
	return resultado;
}

bool Precompilador::procDirectivCondicion(const std::string &valorDirectiva,
		bool verdad) {
	bool resultado = false;
	if(!valorDirectiva.empty()) {
		// Busco si existe la definicion y marco en la pila segun corresponda
		if(this->tablaDef.existeDefinicion(valorDirectiva) == verdad) {
			resultado = this->pilaIfs.marcarDefValida();
		} else {
			resultado = this->pilaIfs.marcarDefInvalida();
		}
	}
	return resultado;
}
